// Copyright Epic Games, Inc. All Rights Reserved.

#include "GameFeatureAction_AddInputBinding.h"
#include "Components/GameFrameworkComponentManager.h"
#include "Engine/GameInstance.h"
#include "GameFramework/PlayerController.h"
#include "Engine/World.h"
#include "GameFramework/Pawn.h"
#include "EnhancedInputSubsystems.h"
#include "Engine/LocalPlayer.h"
#include "Character/LyraHeroComponent.h"
#include "GameFeatures/GameFeatureAction_WorldActionBase.h"
#include "Input/LyraInputConfig.h"

#if WITH_EDITOR
#include "Misc/DataValidation.h" // 数据验证相关
#endif

#include UE_INLINE_GENERATED_CPP_BY_NAME(GameFeatureAction_AddInputBinding) // 包含自动生成的代码

#define LOCTEXT_NAMESPACE "GameFeatures" // 定义本地化文本命名空间

//////////////////////////////////////////////////////////////////////
// UGameFeatureAction_AddInputBinding

/**
 * 游戏特性激活时调用
 */
void UGameFeatureAction_AddInputBinding::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
	FPerContextData& ActiveData = ContextData.FindOrAdd(Context); // 查找或添加上下文数据
	if (!ensure(ActiveData.ExtensionRequestHandles.IsEmpty()) || // 确保扩展请求句柄为空
		!ensure(ActiveData.PawnsAddedTo.IsEmpty())) // 确保PawnsAddedTo为空
	{
		Reset(ActiveData); // 重置数据
	}
	Super::OnGameFeatureActivating(Context); // 调用父类方法
}

/**
 * 游戏特性停用时调用
 */
void UGameFeatureAction_AddInputBinding::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
	Super::OnGameFeatureDeactivating(Context); // 调用父类方法
	FPerContextData* ActiveData = ContextData.Find(Context); // 查找上下文数据

	if (ensure(ActiveData)) // 确保数据有效
	{
		Reset(*ActiveData); // 重置数据
	}
}

#if WITH_EDITOR
/**
 * 数据验证方法
 */
EDataValidationResult UGameFeatureAction_AddInputBinding::IsDataValid(FDataValidationContext& Context) const
{
	EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(Context), EDataValidationResult::Valid); // 组合数据验证结果

	int32 Index = 0; // 索引

	for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs) // 遍历输入配置
	{
		if (Entry.IsNull()) // 检查输入配置是否为空
		{
			Result = EDataValidationResult::Invalid; // 设置为无效
			Context.AddError(FText::Format(LOCTEXT("NullInputConfig", "索引{0}处的InputConfig为空。"), Index)); // 添加错误信息
		}
		++Index; // 递增索引
	}

	return Result; // 返回结果
}
#endif

/**
 * 添加到世界的方法
 */
void UGameFeatureAction_AddInputBinding::AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext)
{
	UWorld* World = WorldContext.World(); // 获取世界
	UGameInstance* GameInstance = WorldContext.OwningGameInstance; // 获取游戏实例
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据

	if ((GameInstance != nullptr) && (World != nullptr) && World->IsGameWorld()) // 检查游戏实例和世界是否有效
	{
		if (UGameFrameworkComponentManager* ComponentManager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>(GameInstance)) // 获取组件管理器
		{
			UGameFrameworkComponentManager::FExtensionHandlerDelegate AddAbilitiesDelegate = // 创建扩展处理委托
				UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(this, &ThisClass::HandlePawnExtension, ChangeContext); // 绑定到处理函数
			TSharedPtr<FComponentRequestHandle> ExtensionRequestHandle = // 创建扩展请求句柄
				ComponentManager->AddExtensionHandler(APawn::StaticClass(), AddAbilitiesDelegate); // 添加扩展处理器

			ActiveData.ExtensionRequestHandles.Add(ExtensionRequestHandle); // 添加扩展请求句柄
		}
	}
}

/**
 * 重置数据的方法
 */
void UGameFeatureAction_AddInputBinding::Reset(FPerContextData& ActiveData)
{
	ActiveData.ExtensionRequestHandles.Empty(); // 清空扩展请求句柄

	while (!ActiveData.PawnsAddedTo.IsEmpty()) // 当PawnsAddedTo不为空时
	{
		TWeakObjectPtr<APawn> PawnPtr = ActiveData.PawnsAddedTo.Top(); // 获取顶部Pawn指针
		if (PawnPtr.IsValid()) // 检查Pawn指针有效
		{
			RemoveInputMapping(PawnPtr.Get(), ActiveData); // 移除输入映射
		}
		else
		{
			ActiveData.PawnsAddedTo.Pop(); // 弹出无效指针
		}
	}
}

/**
 * 处理Pawn扩展的方法
 */
void UGameFeatureAction_AddInputBinding::HandlePawnExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext)
{
	APawn* AsPawn = CastChecked<APawn>(Actor); // 转换为Pawn
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据

	if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved)) // 检查是否是移除事件
	{
		RemoveInputMapping(AsPawn, ActiveData); // 移除输入映射
	}
	else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == ULyraHeroComponent::NAME_BindInputsNow)) // 检查是否是添加事件
	{
		AddInputMappingForPlayer(AsPawn, ActiveData); // 为玩家添加输入映射
	}
}

/**
 * 为玩家添加输入映射的方法
 */
void UGameFeatureAction_AddInputBinding::AddInputMappingForPlayer(APawn* Pawn, FPerContextData& ActiveData)
{
	APlayerController* PlayerController = Cast<APlayerController>(Pawn->GetController()); // 获取玩家控制器

	if (ULocalPlayer* LocalPlayer = PlayerController ? PlayerController->GetLocalPlayer() : nullptr) // 获取本地玩家
	{
		if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) // 获取增强输入子系统
		{
			ULyraHeroComponent* HeroComponent = Pawn->FindComponentByClass<ULyraHeroComponent>(); // 查找英雄组件
			if (HeroComponent && HeroComponent->IsReadyToBindInputs()) // 检查英雄组件存在且准备好绑定输入
			{
				for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs) // 遍历输入配置
				{
					if (const ULyraInputConfig* BindSet = Entry.Get()) // 获取输入配置
					{
						HeroComponent->AddAdditionalInputConfig(BindSet); // 添加额外输入配置
					}
				}
			}
			ActiveData.PawnsAddedTo.AddUnique(Pawn); // 添加Pawn到列表
		}
		else
		{
			UE_LOG(LogGameFeatures, Error, TEXT("未能找到本地玩家的`UEnhancedInputLocalPlayerSubsystem`。输入映射将不会被添加。请确保通过配置文件设置为使用EnhancedInput系统。")); // 记录错误日志
		}
	}
}

/**
 * 移除输入映射的方法
 */
void UGameFeatureAction_AddInputBinding::RemoveInputMapping(APawn* Pawn, FPerContextData& ActiveData)
{
	APlayerController* PlayerController = Cast<APlayerController>(Pawn->GetController()); // 获取玩家控制器

	if (ULocalPlayer* LocalPlayer = PlayerController ? PlayerController->GetLocalPlayer() : nullptr) // 获取本地玩家
	{
		if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) // 获取增强输入子系统
		{
			if (ULyraHeroComponent* HeroComponent = Pawn->FindComponentByClass<ULyraHeroComponent>()) // 查找英雄组件
			{
				for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs) // 遍历输入配置
				{
					if (const ULyraInputConfig* InputConfig = Entry.Get()) // 获取输入配置
					{
						HeroComponent->RemoveAdditionalInputConfig(InputConfig); // 移除额外输入配置
					}
				}
			}
		}
	}

	ActiveData.PawnsAddedTo.Remove(Pawn); // 从列表中移除Pawn
}

#undef LOCTEXT_NAMESPACE // 取消定义本地化文本命名空间